package com.acerola.mrpc.handler;

import com.acerola.mrpc.constant.ReqType;
import com.acerola.mrpc.protocol.Header;
import com.acerola.mrpc.message.RpcProtocol;
import com.acerola.mrpc.message.RpcRequest;
import com.acerola.mrpc.message.RpcResponse;
import com.acerola.mrpc.spring.SpringBeanManager;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * @program: mrpc
 * @description: 服务端事件处理
 * @author: Acerola
 * @create: 2022-12-11 22:53
 **/
@Slf4j
@ChannelHandler.Sharable
public class RpcServerHandler extends SimpleChannelInboundHandler<RpcProtocol<RpcRequest>> {
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, RpcProtocol<RpcRequest> msg) throws Exception {
        log.debug("开始处理消息");
        //需要组装一个RpcResponse类型的完整消息返回
        RpcProtocol<RpcResponse> resProtocol = new RpcProtocol<>();
        Header header = msg.getHeader();
        header.setMessageType(ReqType.RESPONSE.code());
        RpcRequest content = msg.getContent();
        Object invoke = invoke(content);

        resProtocol.setHeader(header);
        RpcResponse response = new RpcResponse();
        response.setData(invoke);
        response.setMsg("success");
        resProtocol.setContent(response);
        ctx.writeAndFlush(resProtocol)
                .addListener(promise -> {
                    if (!promise.isSuccess()) {
                        Throwable cause = promise.cause();
                        log.error("error", cause);
                    }
                });
    }

    private Object invoke(RpcRequest rpcRequest) {
        try {
            Class<?> aClass = Class.forName(rpcRequest.getClassName());
            System.out.println(aClass);
//            Object o = aClass.getDeclaredConstructor().newInstance();
            //通过spring获取接口的实现实例
            Object o = SpringBeanManager.getBean(aClass);
            Method method = aClass.getDeclaredMethod(rpcRequest.getMethodName(), rpcRequest.getParamsTypes());
            return method.invoke(o, rpcRequest.getParams());
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException(e);
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        }
    }
}
